上次透過避免 N+1 問題,我們減少了對資料庫操作的消耗,來避免系統出現效能問題。
不過要能夠在有限的資源下,服務更多的用戶,通常我們會在使用一些方式優化系統。
下面我們來說使用快取來優化系統的方式。
在 Laravel 裡面,我們可以透過把常用的資訊放到運作較快的地方,來提升資料儲存的效率。
目前在正式環境的習慣通常是放在 Redis 裡面。
測試環境為了簡化開發,預設是放在資料庫裡面。所以我們可以很簡單的用 DB::enableQueryLog()
看到效果
比方說,昨天的程式碼
$users = User::with('books')->get();
$books = collect();
foreach ($users as $user) {
$userData = collect();
foreach ($user->books as $book) {
$userData->push($book->title);
}
$books->push($user);
}
我們可以加上一段 Cache::remember
的邏輯,變成
Route::get('/books', function () {
DB::enableQueryLog();
$users = Cache::remember('users_with_books', 600, function () {
return User::with('books')->get(); // 避免 N+1
});
$books = collect();
foreach ($users as $user) {
$userData = collect();
foreach ($user->books as $book) {
$userData->push($book->title);
}
$books->push($user);
}
return DB::getQueryLog();
})->name('books');
這時候我們存取 http://127.0.0.1:8000/books 就會看到
[
{
"query": "select * from \"cache\" where \"key\" in (?)",
"bindings": [
"laravel_cache_users_with_books"
],
"time": 0.19
},
{
"query": "select * from \"users\"",
"bindings": [],
"time": 0.1
},
{
"query": "select * from \"books\" where \"books\".\"user_id\" in (1, 2, 3, 4)",
"bindings": [],
"time": 0.28
},
{
"query": "insert into \"cache\" (\"expiration\", \"key\", \"value\") values (?, ?, ?) on conflict (\"key\") do update set \"expiration\" = \"excluded\".\"expiration\", \"key\" = \"excluded\".\"key\", \"value\" = \"excluded\".\"value\"",
"bindings": [
1758464248,
"laravel_cache_users_with_books",
"TzozOT..."
],
"time": 0.78
}
]
這邊先是試著存取快取的資料表,發現沒有資料之後,改存取 users
和 books
兩張資料表,之後將取得的資料寫入 cache
資料表內。
如果我們再存取一次,就會看見
[
{
"query": "select * from \"cache\" where \"key\" in (?)",
"bindings": [
"laravel_cache_users_with_books"
],
"time": 0.36
}
]
由於快取內有我們要的資料,所以我們只要直接從裡面取出資料即可。
程式撰寫完畢之後,接著我們要在雲端上面建立快取,讓線上的使用者能夠使用到快取的好處。
我們將這段程式碼推到雲端之後,試著存取雲端上的 /books 這個網頁看 Query Log
[
{
"query": "select * from \"cache\" where \"key\" in (?)",
"bindings": [
"ithome2025_cache_users_with_books"
],
"time": 43.38
}
]
我們重新整理之後,會看到即使是拿快取,一樣是存取資料庫
要像是前面所說,存取 Redis 裡面的內容,我們要在 Laravel Cloud 上面加上快取服務
我們可以點擊「Environment」裡面的「Cache」
點擊並安裝之後,我們再次重整畫面看 Query Log,就會看到已經不會透過存取資料庫來取得內容了。所以我們會看到空的 Query Log
[]
今天的部分就到這邊,我們明天見!